package org.jxy.study.rpc.netty.hander;

import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.CharsetUtil;

import java.lang.reflect.Method;
import java.util.Map;

import org.jxy.study.rpc.message.DataMsg;
import org.jxy.study.rpc.message.ErrorCodeEnums;
import org.jxy.study.rpc.message.Request;
import org.jxy.study.rpc.message.Response;
import org.jxy.study.rpc.util.JsonUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author : porteryao
 * @description : 描述
 * @date : 2021/3/12 14:32
 */
@ChannelHandler.Sharable
public class NettyServerRequestHandler extends SimpleChannelInboundHandler<Request> {

    private static final Logger logger = LoggerFactory.getLogger(NettyServerRequestHandler.class);
    //服务实例
    private Map<String, Object> serviceMap;

    public NettyServerRequestHandler(Map<String, Object> serviceMap) {
        this.serviceMap = serviceMap;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        logger.info("已建立新连接，远程连接信息：" + ctx.channel().remoteAddress());
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Request request)
            throws Exception {
        if (serviceMap.isEmpty()) {
            logger.error("没有可用bean");
        }
        final Object instance = serviceMap.get(request.getClassName());
        if (instance != null) {
            Class<?> instanceClass = instance.getClass();
            Method method = instanceClass
                    .getDeclaredMethod(request.getMethodName(), request.getParameterTypes());
            method.setAccessible(true);//避免权限问题
            Object o = method.invoke(instance,
                    parametersConvert(request.getParameterTypes(), request.getParameters()));
            Response response = new Response();
            response.setCode(ErrorCodeEnums.SUCCESS.getCode());
            response.setData(o);
            response.setErrorMsg(ErrorCodeEnums.SUCCESS.getMsg());
            response.setRequestId(request.getId());
            String jsonString = JsonUtil.objectToJsonString(response);
            byte[] data = jsonString.getBytes(CharsetUtil.UTF_8);
            DataMsg dataMsg = new DataMsg(data.length, data);
            ctx.writeAndFlush(dataMsg);
        }
    }

    /**
     * 将参数按照类型还原
     */
    private Object[] parametersConvert(Class<?>[] parameterTypes, Object[] parameters) {
        if (parameters == null || parameters.length == 0) {
            return parameters;
        }
        Object[] parametersOrigin = new Object[parameters.length];
        for (int i = 0; i < parameters.length; i++) {
            Object o = JsonUtil
                    .jsonStringToObject(JsonUtil.objectToJsonString(parameters[i]), parameterTypes[i]);
            if (o != null) {
                logger.info("转换后参数:{}", JsonUtil.objectToJsonString(o));
                parametersOrigin[i] = o;
            }
        }
        return parametersOrigin;
    }

    /**
     * 处理请求过程中的异常
     *
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        if (ctx.channel().isActive()) {
            Response response = new Response();
            response.setCode(ErrorCodeEnums.FAIL.getCode());
            response.setData(null);
            response.setErrorMsg(cause.getMessage());
        }
    }
}
